#ifndef __HLOG_H__
#define __HLOG_H__

/* 
 * 题目要求：
 *  
 * 实现一个日志（或者类似日志数据，只有追加写）落盘的库，希望能够满足高吞吐
 * 量的 写入需求，同时尽量快地将数据持久化。接口自行设计，支持并发调用。另
 * 外请写一个 简单的测试程序，测试一下使用该库在不同存储介质（如 HDD，SSD），
 * 不同吞吐量下的数据写入时延。具体要求：
 * 
 * - 在功能完善的基础上实现尽量简洁，少用第三方库
 * - 写日志接口返回成功时要求保证数据已持久化
 * - 测试每条日志的大小在 100 字节左右
 * 
 */

/* HLOG 支持下面4个日志级别 */
enum {
	HLOG_PRIO_NULL = 0,		//这个级别无用
	HLOG_PRIO_INFO = 1,		//提示信息
	HLOG_PRIO_NOTICE = 2,		//重要信息
	HLOG_PRIO_WARN = 3,		//警告信息
	HLOG_PRIO_ERR = 4,		//错误信息
	HLOG_PRIO_NUM = 5
};

struct hlog_point {
	char *src;
	char *fmt;
	int line_no;
	int prio;
};

extern int g_last_words_piro;		/* 为了保证性能，单独定义这个全局变量 */

#define HLOG_MAX_LEN	256		/* 一行日志的最大长度 */

#define HLOG_LOG(_prio, _fmt, ...) do {		\
	static struct hlog_point hp = {		\
		.src = __FILE__,		\
		.fmt = _fmt,			\
		.line_no = __LINE__,		\
	};					\
	hp.prio = _prio;			\
	if (_prio >= g_last_words_piro)		\
		hlog_log(&hp, ##__VA_ARGS__);	\
}while(0)

#define HLOG_INFO(fmt, ...)	HLOG_LOG(HLOG_PRIO_INFO, fmt, ##__VA_ARGS__)
#define HLOG_NOTICE(fmt, ...)	HLOG_LOG(HLOG_PRIO_NOTICE, fmt, ##__VA_ARGS__)
#define HLOG_WARN(fmt, ...)	HLOG_LOG(HLOG_PRIO_WARN, fmt, ##__VA_ARGS__)
#define HLOG_ERR(fmt, ...)	HLOG_LOG(HLOG_PRIO_ERR, fmt, ##__VA_ARGS__)

/*
 * 初始化HLOG模块, 在使用hlog其他函数之前，必须调用这个函数进行初始化
 *
 * log_file	-- 日志文件
 * mmap_file	-- 共享内存的映射文件
 * persist_prio -- 大于等于这个level的日志信息，会被立即持久化到硬盘，直到写
 *		   盘成功 hlog_log()才返回, 小于这个级别日志不会立即写盘；
 * log_all_prio	-- 大于等于这个这个级别的日志，所有日志都会被写入日志文件。
 * log_prio     -- 大于等于这个级别的日志，只有进程崩溃前的最后32条日志才会被
 *                 写入日志文件。小于这个级别的日志，会被忽略，不记录。
 * 返回值       -- 成功返回0，失败返回错误码；
 * 注意：persist_prio应该大于或者等于log_prio，否则返回-EINVAL；
 *
 */
int hlog_init(char *log_file, char *mmap_file, int persist_prio,
		int log_all_prio, int log_prio);

/* 进程正常退出前调用本函数，通知日志模块把最后的日志刷盘，并释放资源; */
void hlog_exit(void);

/* 不建议外部模块直接调用hlog_log函数，建议调用HLOG_xxx */
void hlog_log(struct hlog_point *hp, ...);

/* 输出hlog模块的统计信息 */
void hlog_dump(void);

#endif //__HLOG_H__


